(function (d3){
    const lineChartData = [
      {
        currency: "USD",
        values: [
          {
            date: "2018/01/01",
            close: 230
          },
          {
            date: "2018/02/01",
            close: 269
          },
          {
            date: "2018/03/01",
            close: 234 
          },
          {
            date: "2018/04/01",
            close: 282 
          },
          {
            date: "2018/05/01",
            close: 231 
          },
          {
            date: "2018/06/01",
            close: 240 
          },
          {
            date: "2018/07/01",
            close: 213 
          },
          {
            date: "2018/08/01",
            close: 320 
          },
          {
            date: "2018/09/01",
            close: 253 
          },
          {
            date: "2018/10/01",
            close: 264 
          },
          {
            date: "2018/11/01",
            close: 272
          },
          {
            date: "2018/12/01",
            close: 290
          }
        ]
      }
    ];
  
    const margin = {
      top: 20,
      bottom: 20,
      left: 50,
      right: 20
    };
  
    const width = 700 - margin.left - margin.right;
    const height = 300 - margin.top - margin.bottom;
    
    const createGradient = select => {
      const gradient = select
        .select('defs')
          .append('linearGradient')
            .attr('id', 'gradient')
            .attr('x1', '0%')
            .attr('y1', '0%')
            .attr('x2', '100%')
            .attr('y2', '0%');
  
     
      const step = 100 / lineChartData[0].values.length;
      const colors = [
        'rgba(25, 255, 255, 0.5)', 'rgba(25, 255, 255, 0.5)', 'rgba(255, 25, 255, 0.5)',
        'rgba(255, 25, 255, 0.5)', 'rgba(255, 255, 25, 0.5)', 'rgba(255, 255, 25, 0.5)', 'transparent', 'rgba(25, 255, 255, 0.5)','rgba(25, 255, 255, 0.5)', 'rgba(255, 25, 255, 0.5)'
      ];
      colors.forEach((item, index) => {
        gradient
        .append('stop')
          .attr('offset', `${step * index}%`)
          .attr('style', `stop-color:${item}`);
      })
  //     gradient
  //       .append('stop')
  //         .attr('offset', '0%')
  //         .attr('style', 'stop-color:#BBF6CA;stop-opacity:0.05');
  
  //     gradient
  //       .append('stop')
  //         .attr('offset', '100%')
  //         .attr('style', 'stop-color:#BBF6CA;stop-opacity:.5');
    }
    
    const createGlowFilter = select => {
      const filter = select
        .select('defs')
          .append('filter')
            .attr('id', 'glow')
  
      filter
        .append('feGaussianBlur')
          .attr('stdDeviation', '4')
          .attr('result', 'coloredBlur');
      
      const femerge = filter
        .append('feMerge');
      
      femerge
        .append('feMergeNode')
        .attr('in', 'coloredBlur');
      femerge
        .append('feMergeNode')
        .attr('in', 'SourceGraphic');
    }
  
    const svg = d3.select('#line-chart')
      .append('svg')
        .attr('width', 700 + margin.left + margin.right)
        .attr('height', 300 + margin.top + margin.bottom)
      .append('g')
        .attr('transform', `translate(${margin.left}, ${margin.top})`);
    
    svg.append('defs');
    svg.call(createGradient);
    svg.call(createGlowFilter);
  
    const parseTime = d3.timeParse('%Y/%m/%d');
    
    const parsedData = lineChartData.map(company => ({
      ticker: company.ticker,
      values: company.values.map(val => ({
        close: val.close,
        date: parseTime(val.date)
      }))
    }));
  
    const xScale = d3.scaleTime()
      .domain([
        d3.min(parsedData, d => d3.min(d.values, v => v.date)),
        d3.max(parsedData, d => d3.max(d.values, v => v.date))
      ])
      .range([0, width]);
    
    const yScale = d3.scaleLinear()
      .domain([
        d3.min(parsedData, d => d3.min(d.values, v => v.close)),
        d3.max(parsedData, d => d3.max(d.values, v => v.close))
      ])
      .range([height, 0]);
    
    const line = d3.line()
      .x(d => xScale(d.date))
      .y(d => yScale(d.close))
      .curve(d3.curveCatmullRom.alpha(0.5));
    
    svg.selectAll('.line')
      .data(parsedData)
      .enter()
      .append('path')
        .attr('d', d => {
          const lineValues = line(d.values).slice(1);
          const splitedValues = lineValues.split(',');
      
          return `M0,${height},${lineValues},l0,${height - splitedValues[splitedValues.length - 1]}`
        })
        .style('fill', 'url(#gradient)')
    
    svg.selectAll('.line')
      .data(parsedData)
      .enter()
      .append('path')
        .attr('d', d => line(d.values))
        .attr('stroke-width', '2')
        .style('fill', 'none')
        .style('filter', 'url(#glow)')
        .attr('stroke', '#47D3DE');
    
    function setFade(selection, opacity) {
      selection.style('opacity', opacity);
    }
    
    const tick = svg.append('g')
      .attr('transform', `translate(0, ${height})`)
      .call(d3.axisBottom(xScale).ticks(12))
      .selectAll('.tick')
      .style('transition', '.2s');
  
    tick
      .selectAll('line')
        .attr('stroke-dasharray', `5, 5`)
        .attr('stroke', '#ccc')
        .attr('y2', `-${height}px`)
    
    tick
      .append('rect')
        .attr('width', `${(width / 12) + 10}px`)
        .attr('x', `-${width / 24 + 5}px`)
        .attr('y', `-${height}px`)
        .attr('height', `${height + 30}px`)
        .style('cursor', 'pointer')
        .style('fill', 'transparent');
      
    svg.selectAll('.tick')
      .append('circle')
        .attr('r', '4px')
        .style('fill', '#72B9FF')
        .attr('cy', (x, i) => - height + yScale(parsedData[0].values[i].close));
    
    tick
      .on('mouseout', function (data, index, elements) {
        d3.selectAll(elements)
          .call(setFade, 1);
      })
      .on('mouseover', function (data, index, elements) {
        d3.selectAll(elements)
          .filter(':not(:hover)')
          .call(setFade, 0.2);
      });
    
    svg.select('.domain')
      .attr('stroke', '#ddd')
  })(d3);